package com.emmmya.ocs.modules.system.security.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.emmmya.ocs.modules.system.security.dao.UrlFilterDao;
import com.emmmya.ocs.modules.system.security.dao.mapper.UrlFilterMapper;
import com.emmmya.ocs.common.base.BaseDao;
import com.emmmya.ocs.modules.system.security.entity.UrlFilter;
import com.emmmya.ocs.modules.system.security.service.DynamicPermissionService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.config.Ini;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.util.CollectionUtils;
import org.apache.shiro.web.config.IniFilterChainResolverFactory;
import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager;
import org.apache.shiro.web.filter.mgt.NamedFilterList;
import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
import org.apache.shiro.web.servlet.AbstractShiroFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.thymeleaf.util.StringUtils;

import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * functional describe:shiro动态权限管理，<br/>
 * 配置权限时，尽量不要使用/**来配置（重置时将被清除，如果要使用，在{}实现类中最后添加key="/**"，value="anon"），每个链接都应该配置独立的权限信息<br/>
 *
 * @author DR.YangLong [410357434@163.com]
 * @version 1.0 2015/1/17 11:10
 */
@Service
@Slf4j
public class DynamicPermissionServiceImpl implements DynamicPermissionService {
    @Autowired
    private ShiroFilterFactoryBean shiroFilterFactoryBean;
    @Autowired
    private UrlFilterDao urlFilterDao;
    @Autowired
    private UrlFilterMapper urlFilterMapper;

    private AbstractShiroFilter shiroFilter;
    //private DynamicPermissionDao dynamicPermissionDao;
    private String definitions = "";

    @PostConstruct
    @Override
    public synchronized void init() {
        log.debug("初始化filter加权限信息，在servlet的init方法之前。");
        reloadPermission();
        log.debug("初始化filter权限信息成功，开始执行servlet的init方法。");
    }
    @Override
    public synchronized void reloadPermission() {
        log.debug("reload资源权限配置开始！");
        try {

            Map<String, String> pers = generateSection();

            if(!CollectionUtils.isEmpty(pers)) {
                DefaultFilterChainManager manager = getFilterChainManager();
                manager.getFilterChains().clear();
                addToChain(manager, pers);
            }
        } catch (Exception e) {
            log.error("reload资源权限配置发生错误！", e);
        }
        log.debug("reload资源权限配置结束！");
    }

    /**
     * 更新其中一个
     */
    @Override
    public synchronized void updateOnePermission(Map<String,String> addMap) throws Exception{
        Map<String, String> oldMap = shiroFilterFactoryBean.getFilterChainDefinitionMap();
        oldMap.putAll(addMap);
        HashMap<String, String> newMap = new HashMap<>();
        newMap.putAll(addMap);
        DefaultFilterChainManager manager = getFilterChainManager();
        manager.getFilterChains().clear();
        shiroFilterFactoryBean.getFilterChainDefinitionMap().clear();
        shiroFilterFactoryBean.setFilterChainDefinitionMap(newMap);
        Map<String, String> chains = shiroFilterFactoryBean.getFilterChainDefinitionMap();
        //过滤器过滤的内容更新
        for (Map.Entry<String, String> entry : chains.entrySet()) {
            String url = entry.getKey();
            String chainDefinition = entry.getValue().trim().replace(" ", "");
            manager.createChain(url, chainDefinition);
        }
    }


    private DefaultFilterChainManager getFilterChainManager() throws Exception {
        if(shiroFilter == null) {
            shiroFilter = (AbstractShiroFilter) shiroFilterFactoryBean.getObject();
        }
        // 获取过滤管理器
        PathMatchingFilterChainResolver filterChainResolver = (PathMatchingFilterChainResolver) shiroFilter
                .getFilterChainResolver();
        DefaultFilterChainManager manager = (DefaultFilterChainManager) filterChainResolver.getFilterChainManager();
        return manager;
    }



    private void addToChain(DefaultFilterChainManager manager, Map<String, String> definitions) throws Exception {
        if (definitions == null || CollectionUtils.isEmpty(definitions)) {
            return;
        }
        manager.getFilterChains().clear();
        shiroFilterFactoryBean.getFilterChainDefinitionMap().clear();
        shiroFilterFactoryBean.setFilterChainDefinitionMap(definitions);
        Map<String, String> chains = shiroFilterFactoryBean.getFilterChainDefinitionMap();
        //移除/**的过滤器链，防止新加的权限不起作用。
        for (Map.Entry<String, String> entry : chains.entrySet()) {
            String url = entry.getKey();
            String chainDefinition = entry.getValue().trim().replace(" ", "");
            manager.createChain(url, chainDefinition);
        }
    }
    @Override
    public synchronized void updatePermission(Map<String, String> newDefinitions) {
        log.debug("更新资源配置开始！");
        try {
            // 获取和清空初始权限配置
            DefaultFilterChainManager manager = getFilterChainManager();
            //newDefinitions.put("/**","anon");
            addToChain(manager, newDefinitions);
            log.debug("更新资源权限配置成功。");
        } catch (Exception e) {
            log.error("更新资源权限配置发生错误!", e);
        }
    }

    /**
     * 将静态配置的资源与要添加的动态资源整合在一起，生成shiro使用的权限map
     * {@see org.apache.shiro.spring.web.ShiroFilterFactoryBean#setFilterChainDefinitions(String)}
     *
     * @return Section
     */
    private Map<String,String> generateSection() {
        Map<String,String> pers = null;
        log.debug("加载本地权限配置");
        Ini ini = new Ini();
        ini.load(definitions); // 加载资源文件节点串定义的初始化权限信息
        Ini.Section section = ini.getSection(IniFilterChainResolverFactory.URLS); // 使用默认节点
        if (CollectionUtils.isEmpty(section)) {
            section = ini.getSection(Ini.DEFAULT_SECTION_NAME);//如不存在默认节点切割,则使用空字符转换
        }
        if (CollectionUtils.isEmpty(section)) {
            pers = new HashMap<String,String>();
        }
        /**
         * 加载非初始化定义的权限信息
         */
        log.debug("加载数据库权限配置");
        Map<String, String> permissionMap = loadDynamicPermission();

        //合并集合
        Map<String, String> newMap1 = rebuildMap(shiroFilterFactoryBean.getFilterChainDefinitionMap(), section);
        pers = rebuildMap(newMap1, permissionMap);
        return pers;
    }

    /**
     * 加载动态权限资源配置,map<ant url,comma-delimited chain definition>
     *     加载数据库维护的接口
     * @return map
     */
    private Map<String, String> loadDynamicPermission() {
        //Map<String,String> map= dynamicPermissionDao.findDefinitionsMap();
        List<UrlFilter> urlFilters = selectByVO(null);
        Map<String,String> map= new HashMap<>();
        urlFilters.forEach(e->{
            map.put(e.getUrl(),e.getDefinition());
        });
        //map.put("/**","anon");
        return map;
    }
    /**
     * 更新数据库中的url到系统
     */
    @Override
    public void updateSystemApi() throws Exception{
        HashMap<String, String> eachMap = new HashMap<>();
        List<UrlFilter> urlFilters = selectByVO(null);
        if(urlFilters.isEmpty()){
            return ;
        }else{
            urlFilters.forEach(e->{
                eachMap.put(e.getUrl(),e.getDefinition());
            });
        }
        Map<String, String> oldMap = shiroFilterFactoryBean.getFilterChainDefinitionMap();
        Map<String, String> newMap = rebuildMap(oldMap, eachMap);
        DefaultFilterChainManager manager = getFilterChainManager();
        Map<String, NamedFilterList> filterChains = manager.getFilterChains();
        manager.getFilterChains().clear();
        shiroFilterFactoryBean.getFilterChainDefinitionMap().clear();
        shiroFilterFactoryBean.setFilterChainDefinitionMap(newMap);
        Map<String, String> chains = shiroFilterFactoryBean.getFilterChainDefinitionMap();
        //过滤器过滤的内容更新
        for (Map.Entry<String, String> entry : chains.entrySet()) {
            String url = entry.getKey();
            String chainDefinition = entry.getValue().trim().replace(" ", "");
            manager.createChain(url, chainDefinition);
        }
    }

    @Override
    public void deleteAndCheck(Long id) {
        UrlFilter urlFilter = get(id);
        delete(id);
        Map<String, String> old = shiroFilterFactoryBean.getFilterChainDefinitionMap();
        old.remove(urlFilter.getUrl());
    }


    /**
     * 查询数据库维护接口
     * @return
     */
    @Override
    public List<UrlFilter> selectByVO(UrlFilter vo){
      return  urlFilterMapper.selectByVO(vo);

    }

    @Override
    public void getListByPage(Page<UrlFilter> page, Wrapper<UrlFilter> wrapper) {
        urlFilterMapper.selectPage(page,wrapper);
    }

    public AbstractShiroFilter getShiroFilter() {
        return shiroFilter;
    }

    public void setShiroFilter(AbstractShiroFilter shiroFilter) {
        this.shiroFilter = shiroFilter;
    }

    public String getDefinitions() {
        return definitions;
    }

    public void setDefinitions(String definitions) {
        this.definitions = definitions;
    }


    @Override
    public BaseDao<UrlFilter, Long> getRepository() {
        return urlFilterDao;
    }

    /**
     * 合并集合
     * @param oldMap        老集合
     * @param addMap        新加的集合
     * @return
     */
    public Map<String,String> rebuildMap(Map<String,String> oldMap,Map<String,String> addMap){
        //新的url权限集合
        LinkedHashMap<String, String> newMap = new LinkedHashMap<>();
        //判断/**是否存在，保持/**是集合最后加入的。
        String s = oldMap.get("/**");
        if(!StringUtils.isEmpty(s)){
            s = oldMap.remove("/**");
        }
        //加入旧集合
        newMap.putAll(oldMap);
        //加入需要添加的集合
        if(!CollectionUtils.isEmpty(addMap)){
            newMap.putAll(addMap);
        }
        //最后加入/**
        if(!StringUtils.isEmpty(s)) {
            newMap.put("/**", s);
        }
        return newMap;
    }
}